use jni::objects::JString;
use jni::sys::{jclass, jint};
use jni::JNIEnv;
use once_cell::sync::Lazy;
use std::sync::Arc;
use tokio::runtime::Runtime;
use tokio::sync::Semaphore;
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
// #[global_allocator]
// static ALLOC: dhat::Alloc = dhat::Alloc;

// Java_对应类完全限定名_方法
static RUNTIME: Lazy<Runtime> = Lazy::new(|| {
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap()
});
#[no_mangle]
pub unsafe extern "C" fn Java_org_example_RustJNI_asyncCallWithRate<'a>(
    env: JNIEnv<'a>,
    _class: jclass,
    requests: JString,
    rate: jint,
) -> JString<'a> {
    let _profiler = dhat::Profiler::new_heap();
    let mut env = env;
    match (|| {
        let rust_request = env.get_string(requests.as_ref()).unwrap();
        let rust_request = rust_request.to_string_lossy().to_owned();
        // 解析请求结果
        let url_vec: Vec<&str> = serde_json::from_str(rust_request.trim()).unwrap();
        // 根据并发数和请求结果进行并发请求
        // 按照请求顺序防止请求结果
        let res_vec = RUNTIME.block_on(dispatch_request(rate, url_vec));
        let res = serde_json::to_string(&res_vec).unwrap();

        let _stats = dhat::HeapStats::get();
        jni::errors::Result::Ok(res)
    })() {
        Ok(res) => env.new_string(res).unwrap(),
        Err(err) => env.new_string(format!("call java error: {err:?}")).unwrap(),
    }
}

/// 分发请求
pub async fn dispatch_request(rate: i32, urls: Vec<&str>) -> Vec<String> {
    let mut handlers = Vec::with_capacity(urls.len());
    let semaphore = Arc::new(Semaphore::new(rate as usize));
    for url in urls.clone() {
        handlers.push(tokio::spawn(do_request(semaphore.clone(), url.to_string())));
    }
    handle_result(handlers).await
}
/// 按照速率请求
pub async fn do_request(semaphore: Arc<Semaphore>, url: String) -> String {
    // 获取信号量
    let _permit = semaphore.acquire().await.unwrap();
    // 进行请求
    let res = reqwest::get(url).await.unwrap().text().await.unwrap();
    // 进行回收
    drop(_permit);
    return res;
}
/// 等待获取结果
pub async fn handle_result(handlers: Vec<tokio::task::JoinHandle<String>>) -> Vec<String> {
    let mut res_vec: Vec<String> = Vec::with_capacity(handlers.len());
    for handler in handlers {
        res_vec.push(handler.await.unwrap());
    }
    return res_vec;
}
